package cn.buk.tms.eotms.dao;

import cn.buk.common.util.DateUtil;
import cn.buk.tms.common.constant.TmsOrderConstant;
import cn.buk.tms.eotms.dao.factory.OperationLogFactory;
import cn.buk.tms.eotms.entity.*;
import cn.buk.tms.eotms.sc.HotelOrderSearchCriteria;
import org.springframework.stereotype.Component;

import jakarta.persistence.criteria.*;
import jakarta.transaction.Transactional;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

import static cn.buk.tms.common.constant.TmsOrderConstant.OPERATING_OBJECT_HOTEL_ORDER;


@Component
@Transactional
public class HotelOrderDaoImpl extends AbstractDao implements HotelOrderDao {

  @Override
  public List<HotelOrder> searchHotelOrders(final int ownerId, final int customerId, HotelOrderSearchCriteria sc) {
    List<HotelOrder> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<HotelOrder> cq = cb.createQuery(HotelOrder.class);
    Root<HotelOrder> root = cq.from(HotelOrder.class);
    root.alias("o");

    var predicates0 = getPredicates_searchHotelOrders(ownerId, customerId, sc, cb, root);


    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<HotelOrder> countRoot = countQuery.from(HotelOrder.class);
    countRoot.alias("o");

    var predicates1 = getPredicates_searchHotelOrders(ownerId, customerId, sc, cb, countRoot);

    // count items
    countQuery.select(cb.count(countRoot)).where(predicates1.toArray(new Predicate[predicates1.size()]));
    Long count = em.createQuery(countQuery).getSingleResult();

    //查询
    cq.select(root).where(predicates0.toArray(new Predicate[predicates0.size()]));

    List<jakarta.persistence.criteria.Order> orderByes = new ArrayList<>();
    orderByes.add(cb.desc(root.get("id")));

    cq.orderBy(orderByes);

    int maxResults = count.intValue();
    if (maxResults > 0) {
      sc.getPage().setRowCount(maxResults);

      results = em.createQuery(cq)
              .setFirstResult(sc.getPage().getFirstPosition())
              .setMaxResults(sc.getPage().getPageSize())
              .getResultList();

//            for (FlightOrder order : results) {
//                order.getFlights().size();
//                order.getPassengers().size();
//                order.getExtras().size();
//            }
    }

    if (results == null) {
      results = new ArrayList<>();
    }

    return results;
  }

  private List<Predicate> getPredicates_searchHotelOrders(int ownerId, int customerId, HotelOrderSearchCriteria sc, CriteriaBuilder cb, Root<HotelOrder> root) {
    List<Predicate> predicates = new ArrayList<>();

    Predicate predicate = cb.conjunction();
    predicates.add(predicate);

    predicate = cb.equal(root.get(HotelOrder_.enterpriseId), ownerId);
    predicates.add(predicate);


    predicate = cb.equal(root.get(HotelOrder_.customerId), customerId);
    predicates.add(predicate);

    if (sc.getBeginDate() != null && sc.getEndDate() != null) {
      predicate = cb.greaterThanOrEqualTo(root.get(HotelOrder_.createTime), sc.getBeginDate());
      predicate = cb.and(predicate, cb.lessThanOrEqualTo(root.get(HotelOrder_.createTime), sc.getEndDate()));
      predicates.add(predicate);
    } else if (sc.getBeginDate() != null) {
      predicate = cb.greaterThanOrEqualTo(root.get(HotelOrder_.createTime), sc.getBeginDate());
      predicates.add(predicate);
    } else if (sc.getEndDate() != null) {
      predicate = cb.lessThanOrEqualTo(root.get(HotelOrder_.createTime), sc.getEndDate());
      predicates.add(predicate);
    }

    if (sc.getName() != null && sc.getName().length() > 0) {
      // 入住人姓名
      predicate = cb.like(root.get(HotelOrder_.passengerName), "%" + sc.getName() + "%");
      predicates.add(predicate);
    }

    if (sc.getHotelName() != null && sc.getHotelName().length() > 0) {
      // 酒店名称
      predicate = cb.like(root.get(HotelOrder_.hotelName), "%" + sc.getHotelName() + "%");
      predicates.add(predicate);
    }

    if (sc.getDepartureDate() != null && sc.getDepartureDate().length() == 10) {
      // 入住日期
      try {
        predicate = cb.equal(root.get(HotelOrder_.checkInDate), DateUtil
                .convertToDate(sc.getDepartureDate(), "yyyy-MM-dd"));
        predicates.add(predicate);
      } catch (ParseException e) {
//        logger.error(e.getMessage());
      }
    }

    if (sc.getStatus() != -1) {
      predicate = cb.equal(root.get(HotelOrder_.status), sc.getStatus());
      predicates.add(predicate);
    }

    if (sc.getOrderNo().length() > 0) {
      predicate = cb.equal(root.get(HotelOrder_.orderNo), sc.getOrderNo());
      predicates.add(predicate);
    }


    if (sc.getOp1().length() > 0) {
      //查找指定用户名的订单
      predicate = cb.equal(root.get(HotelOrder_.operator), sc.getOp1());
      predicates.add(predicate);
    }
    if (sc.getDepartmentId() != null) {
      //只查找本部门的
      List<String> usernames = doGetCustomerDepartmentOperator(ownerId, customerId, sc.getDepartmentId());


      Path<String> path = root.get(HotelOrder_.operator);
      CriteriaBuilder.In<String> in = cb.in(path);
      for(String username: usernames) {
        in.value(username);
      }

      predicates.add(in);
    }
    return predicates;
  }

  @Override
  public HotelOrder getHotelOrderById(int orderId) {
    return em.find(HotelOrder.class, orderId);
  }

  @Override
  public int createHotelOrder(HotelOrder o) {
    em.persist(o);

    OperationLog log = OperationLogFactory.createHotelOrderLog();
    log.setEnterpriseId(o.getEnterpriseId());
    log.setOrderId(o.getId());
    log.setOperator(o.getOperator());
    log.setContent("创建订单");

    em.persist(log);

    return o.getId();
  }

  @Override
  public int cancelHotelOrder(int ownerId, int customerId, String username, int orderId, String remark) {
    int retCode = em.createQuery("update HotelOrder o set o.status = :newStatus, o.lastUpdate = :lastUpdate " +
            "where o.id = :id " +
            "and o.enterpriseId = :enterpriseId " +
            "and o.customer.id = :customerId " +
            "and o.status in (:oldStatus1, :oldStatus2)")
            .setParameter("id", orderId)
            .setParameter("enterpriseId", ownerId)
            .setParameter("customerId", customerId)
            .setParameter("oldStatus1", TmsOrderConstant.HOTEL_ORDER_STATUS_WAITING)
            .setParameter("oldStatus2", TmsOrderConstant.HOTEL_ORDER_STATUS_SUBMITTED)
            .setParameter("newStatus", TmsOrderConstant.HOTEL_ORDER_STATUS_CANCELED)
            .setParameter("lastUpdate", DateUtil.getCurDateTime())
            .executeUpdate();
    if (retCode != 1) {
      throw new RuntimeException("To cancel hotel order failed.");
    }

    OperationLog log = createHotelOrderLog(ownerId, customerId, orderId, username, "取消订单： " + remark);
    em.persist(log);

    return retCode;
  }

  @Override
  public int submitHotelOrder(int ownerId, int customerId, String username, int orderId) {
    int retCode = em.createQuery("update HotelOrder o set o.status = :newStatus, o.lastUpdate = :lastUpdate " +
            "where o.id = :id " +
            "and o.enterpriseId = :enterpriseId " +
            "and o.customer.id = :customerId " +
            "and o.status = :oldStatus")
            .setParameter("id", orderId)
            .setParameter("enterpriseId", ownerId)
            .setParameter("customerId", customerId)
            .setParameter("oldStatus", TmsOrderConstant.HOTEL_ORDER_STATUS_WAITING)
            .setParameter("newStatus", TmsOrderConstant.HOTEL_ORDER_STATUS_SUBMITTED)
            .setParameter("lastUpdate", DateUtil.getCurDateTime())
            .executeUpdate();
    if (retCode != 1) {
      throw new RuntimeException("To cancel hotel order failed.");
    }

    OperationLog log = createHotelOrderLog(ownerId, customerId, orderId, username, "提交订单");
    em.persist(log);

    return retCode;
  }

  @Override
  public int approveHotelOrder(int ownerId, int customerId, String username, int orderId, int denyCode, String denyReason) {
    int retCode = 0;
    if (denyCode == 0) {
      //审批通过
      retCode = em
              .createQuery("update HotelOrder o set o.status = :newStatus, " +
                      "o.approvalInfo.approvalStatus = 1, " +
                      "o.lastUpdate = :lastUpdate " +
                      "where o.id = :id " +
                      "and o.enterpriseId = :enterpriseId " +
                      "and o.customer.id = :customerId " +
                      "and o.status = :oldStatus")
              .setParameter("id", orderId)
              .setParameter("enterpriseId", ownerId)
              .setParameter("customerId", customerId)
              .setParameter("oldStatus", TmsOrderConstant.HOTEL_ORDER_STATUS_SUBMITTED)
              .setParameter("newStatus", TmsOrderConstant.HOTEL_ORDER_STATUS_WAIT_PROCESSING)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();

      if (retCode == 1) {
        OperationLog log = createHotelOrderLog(ownerId, customerId, orderId, username, "审批通过");
        em.persist(log);
      }
    } else {
      //审批拒绝
      retCode = em
              .createQuery("update HotelOrder o set o.status = :newStatus, " +
                      "o.approvalInfo.approvalStatus = 0, " +
                      "o.approvalInfo.approvalDenyCode = :denyCode, " +
                      "o.approvalInfo.approvalDenyReason = :denyReason, " +
                      "o.lastUpdate = :lastUpdate " +
                      "where o.id = :id " +
                      "and o.enterpriseId = :enterpriseId " +
                      "and o.customer.id = :customerId " +
                      "and o.status = :oldStatus")
              .setParameter("id", orderId)
              .setParameter("enterpriseId", ownerId)
              .setParameter("customerId", customerId)
              .setParameter("oldStatus", TmsOrderConstant.HOTEL_ORDER_STATUS_SUBMITTED)
              .setParameter("newStatus", TmsOrderConstant.HOTEL_ORDER_STATUS_CANCELED)
              .setParameter("denyCode", denyCode + "")
              .setParameter("denyReason", denyReason)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();

      if (retCode == 1) {
        OperationLog log = createHotelOrderLog(ownerId, customerId, orderId, username, "审批拒绝(" + denyReason + ")，订单取消");
        em.persist(log);
        retCode = 2;
      }
    }



    return retCode;
  }

  @Override
  public int updateHotelOrderPaid(int userId, int orderId) {
    User user = em.find(User.class, userId);
    HotelOrder hotelOrder = em.find(HotelOrder.class, orderId);
    final int customerId = hotelOrder.getCustomer().getId();

    int retCode = em.createQuery("update HotelOrder o " +
            "set o.payStatus = :payStatus, " +
            "o.lastUpdate = :lastUpdate " +
            "where o.id = :id and (o.payStatus is null or o.payStatus <> :payStatus)")
            .setParameter("id", orderId)
            .setParameter("payStatus", 1)
            .setParameter("lastUpdate", DateUtil.getCurDateTime())
            .executeUpdate();
    if (retCode != 1) {
      throw new RuntimeException("update hotel order pay status failed.");
    }

    OperationLog log = OperationLog.createLog(hotelOrder.getEnterpriseId(), OPERATING_OBJECT_HOTEL_ORDER);
    log.setCustomerId(customerId);
    log.setOperator(user.getUsername());
    log.setOrderId(orderId);
    log.setContent("订单支付完成");
    em.persist(log);

    return retCode;
  }

  private OperationLog createHotelOrderLog(int ownerId, int customerId, int orderId, String username, String remark) {
    OperationLog log = OperationLogFactory.createHotelOrderLog();
    log.setEnterpriseId(ownerId);
    log.setCustomerId(customerId);
    log.setOperator(username);
    log.setOrderId(orderId);
    log.setContent(remark);
    return log;
  }
}
